/*
 * cudanTextureMemory.cpp
 *
 *  Created on: Dec 9, 2009
 *      Author: daniel
 */

namespace CUDAN
{
	template<typename T, int D>
	TextureMemory<T,D>::TextureMemory() : DeviceMemory<T,D>()
	{
#ifdef _DEBUG
		std::cout << "TextureMemory<T,D>::TextureMemory()" << std::endl;
#endif
	}

	template<typename T, int D>
	TextureMemory<T,D>::TextureMemory(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "TextureMemory<T,D>::TextureMemory(HostMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	template<typename T, int D>
	TextureMemory<T,D>::TextureMemory(DeviceMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "TextureMemory<T,D>::TextureMemory(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	template<typename T, int D>
	TextureMemory<T,D>::TextureMemory(CudaArrayMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "TextureMemory<T,D>::TextureMemory(CudaArrayMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	template<typename T, int D>
	TextureMemory<T,D>::TextureMemory(TextureMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "TextureMemory<T,D>::TextureMemory(TextureMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	template<typename T, int D>
	TextureMemory<T,D>* TextureMemory<T,D>::operator=(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "TextureMemory<T,D>* TextureMemory<T,D>::operator=(HostMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	template<typename T, int D>
	TextureMemory<T,D>* TextureMemory<T,D>::operator=(DeviceMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "TextureMemory<T,D>* TextureMemory<T,D>::operator=(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	template<typename T, int D>
	TextureMemory<T,D>* TextureMemory<T,D>::operator=(CudaArrayMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "TextureMemory<T,D>* TextureMemory<T,D>::operator=(CudaArrayMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	template<typename T, int D>
	TextureMemory<T,D>* TextureMemory<T,D>::operator=(TextureMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "TextureMemory<T,D>* TextureMemory<T,D>::operator=(TextureMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy->cudaArray);
		this->texref = copy->texref;

		return this;
	}

	template<typename T, int D>
	TextureMemory<T,D>::~TextureMemory()
	{
#ifdef _DEBUG
		std::cout << "TextureMemory<T,D>::~TextureMemory()" << std::endl;
#endif
	}

	template<typename T, int D>
	bool TextureMemory<T,D>::bind(texture<T, D, cudaReadModeElementType>* copytex)
	{
#ifdef _DEBUG
		std::cout << "bool TextureMemory<T,D>::bind(texture<T, D, cudaReadModeElementType>* copytex)" << std::endl;
#endif
		if(this->cudaArray.array == NULL) {
			std::cout << "Must copy memory to cudaArray before binding." << std::endl;
			return false;
		}

		this->texref = copytex;

		this->texref->normalized = false;
		this->texref->filterMode = /*cudaFilterModeLinear*/cudaFilterModePoint;
		this->texref->addressMode[0] = cudaAddressModeClamp;
		this->texref->addressMode[1] = cudaAddressModeClamp;
		this->texref->addressMode[2] = cudaAddressModeClamp;

		if(cudaBindTextureToArray(*this->texref, this->cudaArray.array, this->cudaArray.channelDesc) == cudaSuccess) return true;
		else return false;
	}

	template<typename T, int D>
	void TextureMemory<T,D>::freeMemory()
	{
#ifdef _DEBUG
		std::cout << "void TextureMemory<T,D>::freeMemory()" << std::endl;
#endif
		this->cudaArray.freeMemory();
	}

	template<typename T, int D>
	void TextureMemory<T,D>::print()
	{
#ifdef _DEBUG
		std::cout << "void TextureMemory<T,D>::print()" << std::endl;
#endif
		HostMemory<T,D> h(this);
		h.print();
		h.freeMemory();
	}

	template<typename T, int D>
	void TextureMemory<T,D>::print(DimensionSizeVector& dim)
	{
#ifdef _DEBUG
		std::cout << "void TextureMemory<T,D>::print(DimensionSizeVector& dim)" << std::endl;
#endif
		HostMemory<T,D> h(this);
		h.print(dim);
		h.freeMemory();
	}

	template<typename T, int D>
	bool TextureMemory<T,D>::allocateMemory(DimensionSizeVector& dim)
	{
#ifdef _DEBUG
		std::cout << "bool TextureMemory<T,D>::allocateMemory(DimensionSizeVector& dim)" << std::endl;
#endif
		return this->cudaArray.allocateMemory(dim);
	}

	template<typename T, int D>
	bool TextureMemory<T,D>::copyFrom(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool TextureMemory<T,D>::copyFrom(HostMemory<T,D>* copy)" << std::endl;
#endif
		return this->cudaArray.copyFrom(copy);
	}

	template<typename T, int D>
	bool TextureMemory<T,D>::copyFrom(DeviceMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool TextureMemory<T,D>::copyFrom(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		return this->cudaArray.copyFrom(copy);
	}

	template<typename T, int D>
	bool TextureMemory<T,D>::copyFrom(CudaArrayMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool TextureMemory<T,D>::copyFrom(CudaArrayMemory<T,D>* copy)" << std::endl;
#endif
		return this->cudaArray.copyFrom(copy);
	}

	template<typename T, int D>
	bool TextureMemory<T,D>::copyFrom(TextureMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool TextureMemory<T,D>::copyFrom(TextureMemory<T,D>* copy)" << std::endl;
#endif
		this->texref = copy->texref;
		return this->cudaArray.copyFrom(&copy->cudaArray);
	}

	template<typename T, int D>
	bool TextureMemory<T,D>::copyTo(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool TextureMemory<T,D>::copyTo(HostMemory<T,D>* copy)" << std::endl;
#endif
		return this->cudaArray.copyTo(copy);
	}

	template<typename T, int D>
	bool TextureMemory<T,D>::copyTo(DeviceMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool TextureMemory<T,D>::copyTo(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		return this->cudaArray.copyTo(copy);
	}

	template<typename T, int D>
	bool TextureMemory<T,D>::copyTo(CudaArrayMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool TextureMemory<T,D>::copyTo(CudaArrayMemory<T,D>* copy)" << std::endl;
#endif
		return this->cudaArray.copyTo(copy);
	}

	template<typename T, int D>
	bool TextureMemory<T,D>::copyTo(TextureMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool TextureMemory<T,D>::copyTo(TextureMemory<T,D>* copy)" << std::endl;
#endif
		copy->texref = this->texref;
		return this->cudaArray.copyTo(&copy->cudaArray);
	}
}
